/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	Application.cpp
*
*	Comments	-	See Application.h
*
**************************************************************************************/

#include "../Include/Application.h"
#include "../Include/WindowingSystem.h"
#include "../Include/Logic.h"
#include "../Include/Scene.h"
#include "../Include/Clock.h"

// Test include
#include "../Include/ComponentModelRenderer.h"
#include "../Include/ComponentLight.h"

namespace Pulse
{
	
	Application::Application( void )
	{

	}

	Application::~Application( void )
	{

	}

	EErrorCode::Type Application::Initialize( void )
	{
		EErrorCode::Type retCode;

		// Get pointer to engine instance
		m_pEngine = Engine::GetInstance();

		// Create instance of the windowing system
		m_pWindowSys = new WindowingSystem;
		m_pWindowSys->Initialize();

		retCode = LoadConfiguration();

		if ( retCode != EErrorCode::OKAY )
		{
			return retCode;
		}

		// Acquire logic
		m_pLogic = CreateApplicationLogic();
		if ( m_pLogic == PSX_NULL )
		{
			PSX_PushError( "No application logic set." );
			return EErrorCode::LOGIC;
		}

		retCode = m_pLogic->Initialize( this );
		if ( retCode != EErrorCode::OKAY )
		{
			PSX_PushError( "Failed to initialize application logic." );
			return EErrorCode::LOGIC;
		}

		return EErrorCode::OKAY;
	}

	EErrorCode::Type Application::Run( const CHAR *pCommandLine )
	{
		// TODO: Read in script file through the pCommandLine argument for dynamic 
		//	window setup and application configuration
		while ( m_pWindowSys->GetNumWindows() )
		{
			Update();
			
			Render();
		}

		return EErrorCode::OKAY;
	}

	void Application::ShutDown( void )
	{
		m_pLogic->Shutdown();
		ReleaseApplicationLogic( m_pLogic );
		m_pLogic = PSX_NULL;

		m_pWindowSys->Shutdown();
		m_pWindowSys = PSX_NULL;

		m_pEngine = PSX_NULL;
	}
	
	EErrorCode::Type Application::LoadConfiguration( void )
	{
		String appName = GetApplicationName();
		//appName += PSX_String("Config.cfg");
		appName += PSX_String(".cfg");

		XMLDocumentPtr pDoc;
		XMLElementPtr pRoot;
		XMLElementPtr pElem;

		pDoc = XMLParser::Load( appName.GetBuffer() );

		if ( pDoc.IsNull() )
		{
			PSX_PushError( "No config file found." );
			return EErrorCode::_ERROR;
		}

		pRoot = pDoc->GetFirstChild();

		if ( pRoot->IsValid() == FALSE )
		{
			PSX_PushError( "Invalid configuration file." );
			return EErrorCode::_ERROR;
		}

		pElem = pRoot->FindChild( PSX_String("CompanyName") );

		if ( pElem->IsValid() )
		{
			m_config.m_companyName = pElem->GetValue();
		}
		else
		{
			PSX_PushError( "No company name specified." );
			return EErrorCode::_ERROR;
		}

		pElem = pRoot->FindChild( PSX_String("ApplicationName") );

		if ( pElem->IsValid() )
		{
			m_config.m_applicationName = pElem->GetValue();
		}
		else
		{
			PSX_PushError( "No application name specified." );
			return EErrorCode::_ERROR;
		}

		pElem = pRoot->FindChild( PSX_String("Version") );

		if ( pElem->IsValid() )
		{
			m_config.m_version = pElem->GetValue();
		}
		else
		{
			PSX_PushError( "No application version specified." );
			return EErrorCode::_ERROR;
		}

		#if PSX_DEBUG
				m_config.m_appDataPath = PSX_String("");
		#else
				String appDataPath = System::GetAppDataDirectory();
				m_config.m_appDataPath = appDataPath + m_config.m_companyName;
				m_config.m_appDataPath += PSX_String("\\");
				m_config.m_appDataPath += m_config.m_applicationName;
				m_config.m_appDataPath += PSX_String("\\");
				m_config.m_appDataPath += m_config.m_version;
				m_config.m_appDataPath += PSX_String("\\");
		#endif

		return EErrorCode::OKAY;
	}

	void Application::Update( void )
	{

		const Clock *pSysClock = m_pEngine->GetClock();
		F64 time = pSysClock->GetTimeSeconds();
		FLOAT dt = pSysClock->GetDeltaSeconds();

		if ( m_pLogic )
		{
			// Per-frame update
			m_pLogic->Update( time, dt );
		}

		m_pEngine->Update();

		m_pWindowSys->Update( dt );
	}

	void Application::Render( void )
	{
		m_pWindowSys->Render();
	}

}